<?php
    /*

     Version: MPL 1.1

     Software distributed under the License is distributed on an "AS IS"
     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
     License for the specific language governing rights and limitations
     under the License.

     The Original Code is KASSIOP Framework.

     The Initial Developer of the Original Code is SURIAN Nicolas (aka NairuS) <me@nairus.fr>.
     Portions created by the Initial Developer are Copyright (C) 2010
     The Initial Developer. All Rights Reserved.

     Contributor(s):

     Alternatively, the contents of this file may be used under the terms
     of the MPL license Version 1.1 (the  "MPL" License"), in which case the
     provisions of Version: MPL 1.1 License are applicable instead of those
     above.  If you wish to allow use of your version of this file only
     under the terms of the MPL License and not to allow others to use
     your version of this file under the MPL, indicate your decision by
     deleting  the provisions above and replace  them with the notice and
     other provisions required by the MPL License.  If you do not delete
     the provisions above, a recipient may use your version of this file
     under either the MPL License.

     The contents of this file are subject to the Mozilla Public License
     Version 1.1 (the "License"); you may not use this file except in
     compliance with the License. You may obtain a copy of the License at
     http://www.mozilla.org/MPL/

    */


    /**
     * Defines the configuration of the application
     *
     * @package    kassiop
     * @subpackage core
     *
     * @author NairuS
     *
     */
    class Configuration
    {
        /**
         * Create an instane of the configuration
         *
         * @param string  $request      The request URI.
         * @param string  $application  The name of the application.
         * @param boolean $debug        Defines the debug mode.
         *
         * @return void
         */
        public function __construct( $request, $application = 'frontend', $debug = false )
        {
            // load the config file.
            $this->manager = new ConfigManager();

            // set the default timeZone.
            self::includeBootstrap();
            self::setDefaultTimeZone( $this->manager->get( APPLICATIONS_DEFAULT_TIME_ZONE_PROPERTY, APPLICATIONS_SECTION ) );

            if( $debug === true )
            {
                self::$debugMode = true;

                ini_set('display_errors', 'on');
                error_reporting((E_ALL | E_STRICT));
            }
            else
            {
                self::$debugMode = false;

                ini_set('display_errors', 'off');
            }

            if( !defined( 'SERVER_NAME' ) )
            {
                define('SERVER_NAME', $this->manager->get( APPLICATIONS_SERVER_NAME_PROPERTY, APPLICATIONS_SECTION ) );
            }

            // defines the root directory (if we call /administration for example)
            $this->application   = $this->manager->get( NAME_PROPERTY, $application );
            $this->rootDirectory = $this->manager->get( ROOT_DIR_PROPERTY, $application ) ;
            $this->configure( $request );
        }

        /**
         * Defines the pattern to build with only the module.
         *
         * @var string
         */
        const REQUEST_PATTERN = '/^\/%s(.*)$/';

        /**
         * Defines the pattern to build with the module and the action.
         *
         * @var string
         */
        const REQUEST_ACTION_PATTERN = '/^\/%s(.*)\/a\/(.*)$/';

        /**
         * Defines the name of the current module.
         * @var string
         */
        public $module ;

        /**
         * Defines the name of the action to load.
         * @var string
         */
        public $action ;

        /**
         * Defines the name of the applicatio to set.
         * @var string
         */
        public $application ;

        /**
         * Defines the default action name.
         *
         * @var string
         */
        protected static $defaultAction = 'index';

        /**
         * Defines the default module name.
         *
         * @var string
         */
        protected static $defaultModule = 'demos';

        /**
         * Defines the ConfigManager instance.
         *
         * @var ConfigManager
         */
        protected $manager;

        /**
         * Defines the name of the current layout.
         * @var string
         */
        protected $layout = "default" ;

        /**
         * Defines the pattern of the request to examinate.
         * @var string
         */
        protected $pattern = '';

        /**
         * Defines the pattern with an action of the request to examinate.
         * @var string
         */
        protected $patternWithAction = '';

        /**
         * Defines the request of the client.
         * @var string
         */
        protected $request = '';

        /**
         * Defines the root directory of the application.
         * @var string
         */
        protected $rootDirectory = '';

        /**
         * Defines if the debug mode is activated or not.
         *
         * @var boolean
         */
        private static $debugMode = false;

        /**
         * Try to include the bootstrap file.
         *
         * @return boolean
         */
        public static function includeBootstrap()
        {
            $bootstrap = realpath( dirname( __FILE__ ) . '/../..' ) . "/bootstrap.php" ;
            if( file_exists( $bootstrap ) )
            {
                include_once $bootstrap ;
                return true ;
            }
            return false ;
        }

        /**
         * Returns true if the debug mode is activated.
         *
         * @return boolean
         */
        public static function isDebug()
        {
            return self::$debugMode;
        }

        /**
         * Sets the default time zone of the application.
         *
         * @param  string $timeZone
         * @return void
         */
        public static function setDefaultTimeZone($timeZone = null)
        {
            if( $timeZone == null )
            {
                $timeZone = 'Europe/Paris';
            }

            //see http://www.php.net/manual/fr/timezones.php
            if( date_default_timezone_get() != $timeZone )
            {
                date_default_timezone_set( $timeZone );
            }
        }

        /**
         * Cleans the root directory for the pattern.
         *
         * @param  string $rootDirectory
         * @return string
         */
        public function cleanRootDirectory( $rootDirectory )
        {
            return str_replace( "/", "\/", $rootDirectory );
        }

        /**
         * Returns the apps libs path of the project.
         * @return string
         */
        public function getAppsLibs()
        {
            Configuration::includeBootstrap() ;
            return LIBS_PATH . $this->manager->get( APPLICATIONS_LIBS_PROPERTY, APPLICATIONS_SECTION ) . DS ;
        }

        /**
         * Return the default module name.
         *
         * @return string
         */
        public function getDefaultModule()
        {
            return self::$defaultModule;
        }

        /**
         * Return the path of the view to include.
         * @return string
         */
        public function getPage()
        {
            $page = $this->buildPage() ;
            return $this->isPageExists( $page ) ? $page : false ;
        }

        /**
         * Return the path of the layout to include.
         * @return string
         */
        public function getLayout()
        {
            $layout = $this->buildLayout() ;
            return $this->isPageExists( $layout ) ? $layout : false ;
        }

        /**
         * Return the pattern to test the request uri without an action called.
         * @return string
         */
        public function getPattern()
        {
            return $this->pattern;
        }

        /**
         * Return the pattern to test the request uri with an action called.
         * @return string
         */
        public function getPatternWithAction()
        {
            return $this->patternWithAction;
        }

        /**
         * Returns the name of the session to get applications vars.
         *
         * @return string
         */
        public function getSessionName()
        {
            self::includeBootstrap();
            $projectName = $this->manager->get( APPLICATIONS_PROJECT_NAME_PROPERTY, APPLICATIONS_SECTION );
            $appName     = $this->application;

            return $projectName != '' ? $projectName . '.' . $appName : $appName;
        }

        /**
         * Return the root directory of the application.
         * @return string
         */
        public function getRootDirectory()
        {
            return $this->rootDirectory;
        }

        /**
         * Includes a partial html/php file.
         *
         * @param  string $module The name of the module where the partial is.
         * @param  string $name   The name of the partial.
         * @param  array $vars    The vars to pass in the partial.
         * @return void
         */
        public function includePartial( $module, $name, array $vars = array() )
        {
            $file = $this->getAppsLibs() . $this->application . '/modules/' . $module . '/templates/' . $name . '.php' ;
            if( $this->isPageExists( $file ) )
            {
                extract( $vars ) ;
                include $file ;
            }
        }

        /**
         * Init the application.
         * Override this method to customize the ignition of the application.
         *
         * @param  CredentialsManager $credentialsManager
         * @throws Exception
         * @return void
         */
        public function init( CredentialsManager $credentialsManager = null )
        {
            // init session
            SessionManager::open() ;

            // set the controller.
            $class = StringsHelper::camelize( $this->module . "_" . $this->application . "_controller" ) ;
            if( class_exists( $class ) )
            {
                $controller = new $class( $this, $credentialsManager ) ;
                if( $controller instanceof Controller )
                {
                    $controller->render() ;
                }
                else
                {
                    throw new Exception( 'The controller must be an instance of Controller!' ) ;
                }
            }
            else
            {
                throw new Exception( 'The controller specified <b>"' . $class .'"</b>doesn\'t exist!' );
            }
        }

        /**
         * Set the name of the layout to include.
         *
         * @return void
         */
        public function setLayout( $layout )
        {
            $this->layout = $layout ;
        }

        /**
         * Builds the path of the current path to include.
         *
         * @return string
         */
        protected function buildPage()
        {
            return $this->getAppsLibs() . $this->application . '/modules/' . $this->module . '/' . $this->action . '.php' ;
        }

        /**
         * Builds the path of the current layout to display.
         *
         * @return string
         */
        protected function buildLayout()
        {
            return $this->getAppsLibs() . $this->application . '/templates/' . $this->layout . '.layout.php' ;
        }

        /**
         * Configure the application.
         * Override this method to customize the $defaultModule and $defaultModule statics.
         *
         * @param  string $request
         * @return void
         */
        protected function configure( $request )
        {
            $ds = '';
            if( $this->rootDirectory != null )
            {
                // add directory separator for the patterns to build.
                $ds = '\/';
                if( !defined( 'DOCUMENT_ROOT' ) )
                {
                    define('DOCUMENT_ROOT', $this->rootDirectory .'/');
                }
            }
            $rootDirectory           = $this->cleanRootDirectory( $this->rootDirectory );
            $this->pattern           = sprintf( self::REQUEST_PATTERN       , $rootDirectory . $ds );
            $this->patternWithAction = sprintf( self::REQUEST_ACTION_PATTERN, $rootDirectory . $ds );

            if( preg_match_all( $this->getPatternWithAction(), $request, $out, PREG_PATTERN_ORDER ) )
            {
                $this->module = isset( $out[1][0] ) && !empty($out[1][0]) ? $out[1][0] : self::$defaultModule;
                $this->action = isset( $out[2][0] ) && !empty($out[2][0]) ? $out[2][0] : self::$defaultAction;
            }
            elseif( preg_match_all( $this->getPattern(), $request, $out, PREG_PATTERN_ORDER ) )
            {
                $this->module = isset($out[1][0]) && !empty($out[1][0]) ? $out[1][0] : self::$defaultModule;
                $this->action = self::$defaultAction;
            }
            else
            {
                $this->module = self::$defaultModule;
                $this->action = self::$defaultAction;
            }
        }

        /**
         * Defines if the view exists.
         *
         * @var string $file defines the file path to check.
         * @return boolean
         */
        protected function isPageExists( $file )
        {
            return file_exists( $file ) && filesize( $file ) > 0 ;
        }
    }
?>